package com.wwg.warehouse.usecase.access

import android.util.ArrayMap
import android.util.Log
import com.google.gson.Gson
import com.google.gson.JsonParser
import com.wwg.warehouse.data.DBEntity
import com.wwg.warehouse.data.whDb
import com.wwg.warehouse.entities.BBookmark
import com.wwg.warehouse.entities.SyncBean
import com.wwg.warehouse.entities.WBookmark
import com.wwg.warehouse.usecase.ServerSyncParser
import com.wwg.warehouse.usecase.access.IAccess.Companion.FOLDER
import com.wwg.warehouse.usecase.access.IAccess.Companion.ROOT
import com.wwg.warehouse.usecase.toBE
import com.wwg.warehouse.usecase.toDb
import com.wwg.warehouse.utils.EncryptUtil
import com.wwg.warehouse.utils.launchCoroutineOnIO
import kotlinx.coroutines.Dispatchers
import java.io.File
import java.util.*
import kotlin.coroutines.Continuation
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.createCoroutine
import kotlin.coroutines.resume

class ObjectModelAccess: IAccess {
    private val parser by lazy { ServerSyncParser() }
    private val routeRecorder by lazy { Stack<String>() }

    override fun initializeDB() {
        launchCoroutineOnIO {
            val content = parser.loadAsserts()
            Log.i(TAG, "${content.info?.settings?.bookmarks?.checksum}")
            val root = content.info?.settings?.bookmarks?.roots
            //write to db
            val children = mutableListOf<WBookmark>()
            root?.synced?.run {
                children.add(this)
            }
            root?.bookmarkBar?.run {
                children.add(this)
            }
            root?.other?.run {
                children.add(this)
            }

            val tree = WBookmark(name = ROOT, path = "", type = "folder", children = children)
            beforeTraversals(tree)
            doPersist(tree)
        }
    }

    private fun beforeTraversals(tree: WBookmark) {
        val dbTree = tree.toDb()
        // 父节点信息
        dbTree.parentName = ""
        dbTree.parentPath = ""

        whDb.bookmarkDao.insert(dbTree)
    }

    private fun doPersist(tree: WBookmark) {
        val children = tree.children ?: return

        tree.path = getPath()
        routeRecorder.push(tree.name)
        children.forEach {
            Log.i(TAG, "parent : ${tree.name}, self: ${it.name}")
            val dbEntity = correctMap(tree, it)
            whDb.bookmarkDao.insert(dbEntity)
            if (FOLDER == it.type) {
                doPersist(it)
            }
        }

        routeRecorder.pop()
    }

    private fun correctMap(parent: WBookmark, self: WBookmark): DBEntity {
        val dbEntity = self.toDb()
        // 父节点信息
        dbEntity.parentName = parent.name
        dbEntity.parentPath = parent.path ?: ""

        // path 信息
        dbEntity.path = getPath()

        // 注入 uid, state, order

        return dbEntity
    }

    private fun getPath(): String {
        val size = routeRecorder.size
        if (size <= 0) {
            return ""
        }

        val sb = StringBuilder()

        for (index in 0 until size) {
            sb.append(routeRecorder[index])
            sb.append(File.separator)
        }

        return if (sb.length > IAccess.MD5_LENGTH) {
            EncryptUtil.md5Encrypt(sb.toString())
        } else {
            sb.toString()
        }
    }

    override fun getSubTree(name: String, path: String, deep: Int): List<BBookmark> {
        val indexMap = ArrayMap<Pair<String, String>, BBookmark>()
        val subTree = whDb.bookmarkDao.querySubTree(name, path, deep)
        subTree.forEach {
            val index = Pair(it.name, it.path)
            it.toBE()
        }
    }

    fun initDBWithFile() = suspend {
        parser.loadFile()
    }.createCoroutine(object : Continuation<SyncBean> {
        override val context: CoroutineContext = Dispatchers.IO
        override fun resumeWith(result: Result<SyncBean>) {
            Log.i(TAG, "${result.isSuccess} ${result.getOrNull()?.settings?.bookmarks?.checksum}")
            //write to db
        }
    }).resume(Unit)

    fun keepBookmarks() {
        val info = parser.loadAsserts().info
//        bean = info

        val json = Gson().toJson(info)
//        serializeBean = json
        JsonParser.parseString(json).asJsonObject
    }

    companion object {
        private const val TAG = "ObjectModelAccess"
    }
}